/**
 * Author(s): xuming.Wong <xuming.Wong@gmail.com>
 */
#include "WOWArchive.h"

#include <algorithm>
#include <string>
#include "CharacterModelManager.h"
#include "NativeFile.h"
#include "MapDatabase.h"

namespace PQGameCore
{
	WOWArchive::WOWArchive()
		: _list(),_fileList()
	{
	}

	bool WOWArchive::isLeafPath(std::string path)
	{
		int size=_list.size();
		for(int i=0;i<size;i++){
			MPQTreeNode* node=_list[i]->getTreeNode(path);
			if(MPQTreeNode::isLeaf(node)){
				return true;
			}
		}
		return false;
	}

	bool WOWArchive::fileExist(std::string path)
	{
		int size=_list.size();
		for(int i=0;i<size;i++){
			if(_list[i]->fileExist(path.c_str())){
				return true;
			}
		}
		return false;
	}

	/*
	*/
	void WOWArchive::init()
	{
		char *gamepath="C:\\World of Warcraft\\Data\\";
		
		const char* archiveNames[] = {"lichking.MPQ", "expansion.MPQ", "common-2.MPQ", "common.MPQ", 
			"enUS\\lichking-locale-enUS.MPQ", "enUS\\expansion-locale-enUS.MPQ", "enUS\\locale-enUS.MPQ", 
			"enGB\\lichking-locale-enGB.MPQ", "enGB\\expansion-locale-enGB.MPQ", "enGB\\locale-enGB.MPQ", 
			"deDE\\lichking-locale-deDE.MPQ", "deDE\\expansion-locale-deDE.MPQ", "deDE\\locale-deDE.MPQ",
			"frFR\\lichking-locale-frFR.MPQ", "frFR\\expansion-locale-frFR.MPQ", "frFR\\locale-frFR.MPQ",
			"zhTW\\lichking-locale-zhTW.MPQ", "zhTW\\expansion-locale-zhTW.MPQ", "zhTW\\locale-zhTW.MPQ",
			"ruRU\\lichking-locale-ruRU.MPQ", "ruRU\\expansion-locale-ruRU.MPQ", "ruRU\\locale-ruRU.MPQ",
			"esES\\lichking-locale-esES.MPQ", "esES\\expansion-locale-esES.MPQ", "esES\\locale-esES.MPQ",
			"koKR\\lichking-locale-koKR.MPQ", "koKR\\expansion-locale-koKR.MPQ", "koKR\\locale-koKR.MPQ",
			"zhCN\\lichking-locale-zhCN.MPQ", "zhTW\\expansion-locale-zhCN.MPQ", "zhTW\\locale-zhCN.MPQ"
			
			};

		char path[512];

		// patch goes first -> fake priority handling
		sprintf(path, "%s%s", gamepath, "patch-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "patch.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "enUS\\Patch-enUS-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "enUS\\Patch-enUS.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "enGB\\Patch-enGB-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "enGB\\Patch-enGB.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "deDE\\Patch-deDE.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "deDE\\Patch-deDE-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "frFR\\Patch-frFR-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "frFR\\Patch-frFR.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "zhTW\\Patch-zhTW-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "zhTW\\Patch-zhTW.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "ruRU\\Patch-ruRU-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "ruRU\\Patch-ruRU.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "esES\\Patch-esES-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "esES\\Patch-esES.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "koKR\\Patch-koKR-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "koKR\\Patch-koKR.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "zhCN\\Patch-zhCN-2.MPQ");
		initMPQArchive(path);

		sprintf(path, "%s%s", gamepath, "zhCN\\locale-zhCN.MPQ");
		initMPQArchive(path);

		for (int i=0; i<31; i++) {
			sprintf(path, "%s%s", gamepath, archiveNames[i]);
			initMPQArchive(path);
		}

		initDatabases();
	}

	void WOWArchive::initDatabases()
	{
		//SMapDatabase.init();
	}

	void WOWArchive::convertChrModels()
	{
		if(PQEngine::NativeFile::isExist(CharacterModelManager::PERSIS_FILE_NAME)){
			return;
		}
		std::vector<std::string> races= WOWArchive::getFileList("character");
		int size=races.size();
		for(int i=0;i<size;i++){
			SCharacterModelMgr.addChrRaceName(races[i]);
			std::string modelPath="character\\"+races[i]+"\\male";
			std::vector<std::string> models=WOWArchive::getFileList(modelPath);
			int modelSize=models.size();
			for(int j=0;j<modelSize;j++){
				SCharacterModelMgr.addMaleChrModel(races[i],models[j]);
			}

			modelPath="character\\"+races[i]+"\\female";
			models=WOWArchive::getFileList(modelPath);
			modelSize=models.size();
			for(int j=0;j<modelSize;j++){
				SCharacterModelMgr.addFemaleChrModel(races[i],models[j]);
			}
		}

		SCharacterModelMgr.serialize();
		
	}


	void WOWArchive::initMPQArchive(std::string path)
	{
		MPQArchive* archive= MPQArchive::openArchive(path);
		if(archive){
			_list.push_back(archive);
		}
	}


	std::vector<std::string> WOWArchive::getFileList(std::string path)
	{
		std::vector<std::string> list;
		int size=_list.size();
		std::string name="";
		for(int i=0;i<size;i++){
			MPQTreeNode* child=_list[i]->getTreeNode(path);
			if(child){
				int listSize=list.size();
				for(int j=0;j<child->getChildrenCount();j++){
					bool find=false;
					name=child->getChildName(j);
					for(int k=0;k<listSize;k++){
						
						if(name==list[k]){
							find=true;
							break;
						}
					}
					if(!find){
						list.push_back(name);
					}
				}
			}
		}
		return list;
	}

	M2File* WOWArchive::openM2File(std::string path)
	{
		MPQFile* file=openMPQFile(path);//add opened list?
		if(!file){
			return 0;
		}

		M2File* f=new M2File(file);
		return f;
	}

	M2SkinFile* WOWArchive::openM2SkinFile(std::string path)
	{
		MPQFile* file=openMPQFile(path);
		if(!file){
			return 0;
		}

		M2SkinFile* f=new M2SkinFile(file);
		return f;
	}

	M2AnimFile* WOWArchive::openM2AnimFile(std::string path)
	{
		MPQFile* file=openMPQFile(path);
		if(!file){
			return 0;
		}

		M2AnimFile* f=new M2AnimFile(file);
		return f;
	}


	BLPFile* WOWArchive::openBLPFile(std::string path)
	{
		MPQFile* file=openMPQFile(path);
		if(!file){
			return 0;
		}

		BLPFile* f=new BLPFile(file);
		return f;
	}


	MPQFile* WOWArchive::openMPQFile(std::string path)
	{
		int size=_list.size();
		for(int i=0;i<size;i++){
			MPQFile* file=_list[i]->openFile(path.c_str());
			if(file){
				_fileList.insert(MPQFileList::value_type(path,file));//add into opened mpq files
				return file;
			}
		}
		return 0;
	}

	void WOWArchive::closeMPQFile(std::string path)
	{
		MPQFileList::iterator it=_fileList.find(path);
		if(it!=_fileList.end()){
			if(it->second){
				delete it->second;
			}
			_fileList.erase(it);
			
		}
	}
	
	WOWDbcFile* WOWArchive::openDbcFile(std::string path)
	{
		MPQFile* file=openMPQFile(path);
		if(!file){
			return 0;
		}

		WOWDbcFile* dbc=new WOWDbcFile(file);
		return dbc;
	}

	WdtFile* WOWArchive::getWdtFile(int index)
	{
		return SMapDatabase.getWdtFile(index);
	}

	WdlFile* WOWArchive::getWdlFile(int index)
	{
		return SMapDatabase.getWdlFile(index);
	}

}

